﻿using System;

using Microsoft.VisualStudio.TestTools.UnitTesting;

using PublicDomain.Framework.UnitTesting;

namespace PublicDomain.UnitTest.Framework.UnitTesting
{
    [TestClass]
    public class AssertExtensionsTest
    {
        [TestMethod]
        [Description("Tests ArgumentException.Throws for the basic positive case.")]
        public void Throws1Test()
        {
            ArgumentException argumentException;

            AssertExtensions.Throws<ArgumentException>(
                () => { throw new ArgumentException("argumentA is invalid.", "argumentA"); },
                "argumentA is invalid.\r\nParameter name: argumentA",
                out argumentException);

            Assert.AreEqual("argumentA", argumentException.ParamName);
        }

        [TestMethod]
        [Description("Tests ArgumentException.Throws for the case when actual exception type doesn't match expected one.")]
        public void Throws2Test()
        {
            ArgumentException argumentException;

            AssertExtensions.Throws<AssertFailedException>(
                () =>
                AssertExtensions.Throws<ArgumentException>(
                    () => 
                    { 
                        throw new ArgumentNullException("argumentA", "argumentA is invalid."); 
                    },
                    "argumentA is invalid.\r\nParameter name: argumentA",
                    out argumentException),
                "Assert.Fail failed. Expected exception of type 'System.ArgumentException' has not been thrown. An exception of type 'System.ArgumentNullException' has been thrown instead.");
        }

        [TestMethod]
        [Description("Tests ArgumentException.Throws for the case when actual exception message doesn't match expected one.")]
        public void Throws3Test()
        {
            ApplicationException actualException;

            AssertExtensions.Throws<AssertFailedException>(
                () =>
                AssertExtensions.Throws<ApplicationException>(
                    () => 
                    { 
                        throw new ApplicationException("Actual Message."); 
                    },
                    "Expected Message.",
                    out actualException),
                    "Assert.AreEqual failed. Expected:<Expected Message.>. Actual:<Actual Message.>. ");
        }

        [TestMethod]
        [Description("Tests ArgumentException.Throws for the case when actual exception type doesn't match expected one.")]
        public void Throws4Test()
        {
            ApplicationException actualException;

            AssertExtensions.Throws<AssertFailedException>(
                () =>
                AssertExtensions.Throws<ApplicationException>(
                    () => 
                    { 
                        throw new Exception("Message1."); 
                    },
                    "Message.",
                    out actualException),
                    "Assert.Fail failed. Expected exception of type 'System.ApplicationException' has not been thrown. An exception of type 'System.Exception' has been thrown instead.");
        }

        [TestMethod]
        [Description("Tests ArgumentException.Throws for the case when expected exception has not been trown.")]
        public void Throws5Test()
        {
            ApplicationException actualException;

            AssertExtensions.Throws<AssertFailedException>(
                () =>
                AssertExtensions.Throws<ApplicationException>(
                    () => 
                    { 
                    },
                    "Message.",
                    out actualException),
                "Assert.Fail failed. Expected exception of type 'System.ApplicationException' has not been trown.");
        }

        [TestMethod]
        [Description("Tests ArgumentException.ThrowsArgumentNullException with full set of arguments for the basic positive case.")]
        public void ArgumentNullException1Test()
        {
            ArgumentNullException actualException;

            AssertExtensions.ThrowsArgumentNullException(
                () => { throw new ArgumentNullException("argumentA", "argumentA is invalid."); },
                "argumentA is invalid.\r\nParameter name: argumentA",
                "argumentA",
                out actualException);
        }

        [TestMethod]
        [Description("Tests an overload of ArgumentException.ThrowsArgumentNullException with minimum set of arguments for the basic positive case.")]
        public void ArgumentNullException2Test()
        {
            AssertExtensions.ThrowsArgumentNullException(
                () => { throw new ArgumentNullException("argumentA"); },
                "argumentA");
        }

        [TestMethod]
        [Description("Tests ArgumentException.ThrowsArgumentException with full set of arguments for the basic positive case.")]
        public void ThrowsArgumentException1Test()
        {
            ArgumentException actualException;

            AssertExtensions.ThrowsArgumentException(
                () => { throw new ArgumentException("argumentA is invalid.", "argumentA"); },
                "argumentA is invalid.\r\nParameter name: argumentA",
                "argumentA",
                out actualException);
        }

        [TestMethod]
        [Description("Tests ArgumentException.Equals(byte[] expected, byte[] actual) for the basic positive case.")]
        public void EqualsByteArrayBasicTest()
        {
            var expected = new byte[2] { 12, 21 };
            var actual = new byte[2] { 12, 21 };

            AssertExtensions.Equals(expected, actual);
        }

        [TestMethod]
        [Description("Tests ArgumentException.Equals(byte[] expected, byte[] actual) for the case of empty expected and actual arrays.")]
        public void EqualsByteArrayEmptyExpectedAndActualArraysTest()
        {
            var expected = new byte[0];
            var actual = new byte[0];

            AssertExtensions.Equals(expected, actual);
        }

        [TestMethod]
        [Description("Tests ArgumentException.Equals(byte[] expected, byte[] actual) for the case - The expected array length doesn't match actual array length.")]
        public void EqualsByteArrayDifferentLengthOfExpectedAndActualArraysTest()
        {
            var expected = new byte[1];
            var actual = new byte[0];

            AssertExtensions.Throws<AssertFailedException>(
                () => AssertExtensions.Equals(expected, actual),
                "Assert.AreEqual failed. Expected:<1>. Actual:<0>. The expected array length doesn't match actual array length.");
        }

        [TestMethod]
        [Description("Tests ArgumentException.Equals(byte[] expected, byte[] actual) for the case - The expected byte array value of the index '{0}' doesn't match the actual byte array value of the same index.")]
        public void EqualsByteArrayItemsDoNotMatchTest()
        {
            var expected = new byte[2] { 12, 21 };
            var actual = new byte[2] { 12, 99 };

            AssertExtensions.Throws<AssertFailedException>(
                () => AssertExtensions.Equals(expected, actual),
                "Assert.AreEqual failed. Expected:<21>. Actual:<99>. The expected byte array value of the index '1' doesn't match the actual byte array value of the same index.");
        }
    }
}
